/**
 * @fileoverview
 * This script defines utilities for interacting with data from www.fly-ted.org.
 * @author <a href="http://purl.org/net/aliman">Alistair Miles</a>, Graham Klyne, Jun Zhao
 * @version $Revision:538 $ on $Date: 2008-08-27 09:08:41 +0100 (Wed, 27 Aug 2008) $ by $Author: aliman $
 * @requires YAHOO.util.Connect
 * @requires flyui.flyted.GeneNameMappings
 * TODO license terms
 */

// create a namespace if not already defined
flyui.namespace("flyui.flyted");




flyui.flyted.provenance = "retrieved on 2008-12-03";




/**
 * TODO doc me
 */
flyui.flyted.Service = function (endpointURL) {
	/**
	 * @private
	 */
	this._endpoint = endpointURL;
};


// extend
flyui.flyted.Service.prototype = new flyui.sparql.Service();


/**
 * TODO doc me
 */
flyui.flyted.Service.prototype.findImagesByFlytedProbeName = function( probeName, success, failure ) {
    var _context = "flyui.flyted.Service.prototype.findImagesByFlytedProbeName";
	try {
		flyui.info("probeName: "+probeName, _context);
//		var successAdapter = flyui.flyted.Service._buildSuccessAdapterForFindImagesByFlytedProbeName(success);
        var successChain = flyui.chain(flyui.flyted.Service.responseToImages, success);	
		var query = flyui.flyted.Service._buildQueryForFindImagesByFlytedProbeName(probeName);
		this.query(query, successChain, failure);
	}catch (error) {
        throw new flyui.UnexpectedException(_context, error);
    }
};


/**
 * Find images in the FlyTED database for the given flybase gene ID.
 * @param {String} flybaseGeneID the flybase gene ID e.g. FBgn012345
 * @param {Function} success the success case callback function, which must accept an array of 
 * flyui.flyted.Image objects
 * @param {Function} failure the failure case callback function, which must accept a YUI HTTP response object
 */
flyui.flyted.Service.prototype.findImagesByFlybaseGeneID = function( flybaseGeneID, success, failure) {
    var _context = "flyui.flyted.Service.prototype.findImagesByFlybaseGeneID";
	try {
		flyui.info("flybaseGeneID: "+flybaseGeneID, _context);
//		var successAdapter = flyui.flyted.Service._buildSuccessAdapterForFindImagesByFlybaseGeneID(success);
        var successChain = flyui.chain(flyui.flyted.Service.responseToImages, success); 
		var query = flyui.flyted.Service._buildQueryForFindImagesByFlybaseGeneID(flybaseGeneID);	
		this.query(query, successChain, failure);
	}catch (error) {
        throw new flyui.UnexpectedException(_context, error);
    }
	
};

flyui.flyted.Service.prototype.findImagesByFlybaseGeneIDBatch = function( flybaseGeneIDs, success, failure) {
    var _context = "flyui.flyted.Service.prototype.findImagesByFlybaseGeneIDBatch";
	try {
		flyui.info("flybaseGeneIDs: "+flybaseGeneIDs, _context);
		if (flybaseGeneIDs.length == 0) {
            success({});
        }
        else {
            var chain = flyui.chain(flyui.flyted.Service.transformResponseForFindImagesByFlybaseGeneIDBatch, success);
            var query = this._buildQueryForFindImagesByFlybaseGeneIDBatch(flybaseGeneIDs);
            flyui.debug("query: "+query, _context);
            this.postQuery(query, chain, failure);        
        }		
	}catch (error) {
        throw new flyui.UnexpectedException(_context, error);
    }
	
};

flyui.flyted.Service.prototype._buildQueryForFindImagesByFlybaseGeneIDBatch = function( flybaseGeneIDs ) {
    var _context = "flyui.flyted.Service.prototype._buildQueryForFindImagesByFlybaseGeneIDBatch";
    try {
        /*
        # query to select data on multiple genes
        
        PREFIX flyted: <http://purl.org/net/flyted/schema/>  
                
        SELECT DISTINCT ?fbgn ?flytedURL ?fullImageURL ?thumbnailURL ?probe ?caption ?probeLabel WHERE 
        {
          {
            {
              LET (?fbgn := <http://openflydata.org/id/flybase/feature/FBgn0004903> )
            }
            UNION
            {
              LET (?fbgn := <http://openflydata.org/id/flybase/feature/FBgn0033960> )
            }
          }
          {
            ?probe flyted:hybridisesTranscriptOf ?fbgn ;
              		rdfs:label ?probeLabel .
            ?fullImageURL flyted:probe ?probe ;
              			  flyted:thumbnail ?thumbnailURL;
              			  rdfs:seeAlso ?flytedURL;
              			  rdfs:label ?caption .
            
          }
        }
        */
    	
    	var query = 	"PREFIX flyted: <http://purl.org/net/flyted/schema/> " +
						"PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> " +
						"PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> ";
						                            
        query +=            "SELECT DISTINCT ?fbgn ?flytedURL ?fullImageURL ?thumbnailURL ?probe ?caption ?probeLabel  WHERE \n " +
                            "{\n" +
                            "  {\n" +
                            "    { LET (?fbgn := <http://openflydata.org/id/flybase/feature/"+flybaseGeneIDs[0]+"> ) }\n";
                            
        for (var i=0;i<flybaseGeneIDs.length;i++) {
            query +=        "    UNION\n" +
                            "    { LET (?fbgn := <http://openflydata.org/id/flybase/feature/"+flybaseGeneIDs[i]+"> ) }\n";
        }
        
        query +=            "  }\n" +
                            "  {\n" +
                            "    ?probe flyted:hybridisesTranscriptOf ?fbgn ;\n" +
                            "			rdfs:label ?probeLabel .\n" +
							"	?fullImageURL flyted:probe ?probe ; \n" +
							"				  flyted:thumbnail ?thumbnailURL; \n" +
							"				  rdfs:seeAlso ?flytedURL; \n" +
							"				  rdfs:label ?caption .\n" +
						    "  }\n" +
                            "}";  
                            
        flyui.debug("the raw query: "+query, _context);
        
        return query;
    } 
    catch (unexpected) {
        flyui.debug("rethrowing "+unexpected.name+", "+unexpected.message, _context);
        throw unexpected;    
    }    
};


flyui.flyted.Service.responseToImages = function( response ) {
    var _context = "flyui.flyted.Service.responseToImages";
    try {
        flyui.debug("response status: "+response.status, _context);
        flyui.debug("try parsing response text as json", _context);
        flyui.debug("response text: "+response.responseText, _context);
        var resultSet = YAHOO.lang.JSON.parse(response.responseText);
        flyui.debug("convert result set to an array of genes", _context);
        var images = flyui.flyted.Image.newInstancesFromSPARQLResults(resultSet);
        return images;
    } catch (e) {
        flyui.debug("caught "+e.name+", "+e.message, _context);
        throw new flyui.UnexpectedException(_context, e);
    }
};



/**
 * Build a SPARQL query to retrieve images by flyted probe name.
 * @param {String} anyName the probe name to search by
 * @return a SPARQL query
 * @type String
 * @private
 * @static
 */
flyui.flyted.Service._buildQueryForFindImagesByFlytedProbeName = function( probeName ) {

	try {
		var prefixes = 	"PREFIX flyted: <http://purl.org/net/flyted/schema/> " +
						"PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> " +
						"PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> ";
						
		var body = 		"SELECT DISTINCT *  WHERE { " +
							"?fullImageURL " +
								"flyted:probe ?probe ; " +
								//"flyted:associatesToGene ?gene ; " +
								"flyted:thumbnail ?thumbnailURL; " +
								"rdfs:seeAlso ?flytedURL; " +
								"rdfs:label ?caption ." +
							"?probe rdfs:label '" + probeName + "' ." +
						"}";
							
		var query = prefixes + body;
	
		return query;
	}catch (error) {
        throw new flyui.UnexpectedException("flyui.flyted.Service._buildQueryForFindImagesByFlytedProbeName", error);
    }
};

flyui.flyted.Service._buildQueryForFindImagesByFlybaseGeneID = function( flybaseGeneID ) {
	try {
		var prefixes = 	"PREFIX flyted: <http://purl.org/net/flyted/schema/> " +
						"PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> " +
						"PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> ";
						"PREFIX so: <http://purl.org/obo/owl/SO#> ";
						
		var body = 		"SELECT DISTINCT ?fullImageURL ?thumbnailURL ?flytedURL ?caption ?probe ?probeLabel WHERE { " +
							"?probe flyted:hybridisesTranscriptOf <http://openflydata.org/id/flybase/feature/" + flybaseGeneID + "> ;" +
								"rdfs:label ?probeLabel ." +
							"?fullImageURL " +
								"flyted:probe ?probe ; " +
								"flyted:thumbnail ?thumbnailURL; " +
								"rdfs:seeAlso ?flytedURL; " +
								"rdfs:label ?caption ." +
						"}";
							
		var query = prefixes + body;
	
		return query;
	}catch (error) {
        throw new flyui.UnexpectedException("flyui.flyted.Service._buildQueryForFindImagesByFlybaseGeneID", error);
    }
};



/**
 * Map a string to a list of strings via a supplied mapping table,
 * returnimng an empty list if the supplied key is not present. 
 * @param {String} key 		a key value to be mapped
 * @param {Object} table 	an object with members that are arrays of strings
 * @return an array of string values, which may be empty if the given key is not found
 * @type [String]
 */
flyui.flyted.Service.mapNameUsingTable = function ( key, table ) {
	try {
		var result = table[key];
		if (typeof result == "undefined" || !result ) {
			result = [];
		}
		return result;
	}catch (error) {
        throw new flyui.UnexpectedException("flyui.flyted.Service.mapNameUsingTable", error);
    }
};


/**
 * TDO doc me
 */
flyui.flyted.Image = function () {
	
	/**
	 * @type String
	 */
	this.fullImageURL = null;
	
	/**
	 * @type String
	 */
	this.thumbnailURL = null;
	
	/**
	 * @type String
	 */
	 
	this.flytedURL = null;
	
	/**
	 * @type String
	 */
	this.caption = null;
	
	/**
	 * @type String
	 */
	this.probe = null;
	

};


/**
 * TODO doc me
 */
flyui.flyted.Image.newInstancesFromSPARQLResults = function(resultSet){
	try {
		var bindings = resultSet.results.bindings;
		var imagePool = new flyui.flyted.ImagePool();
		var probePool = new flyui.flyted.ProbePool();
		
		for (var i=0; i<bindings.length; i++) {
			var binding = bindings[i];
			
			var imageURI = binding.fullImageURL.value;
			//TODO
			var image = imagePool.get(imageURI);
//			image.fullImageURL = binding.fullImageURL.value;
			image.thumbnailURL = binding.thumbnailURL.value;
			image.flytedURL = binding.flytedURL.value;
			image.caption = binding.caption.value;
			
			if (binding.probe){
				var probeURI = binding.probe.value;
				var probe = probePool.get(probeURI);
				
				if (!probe.probeLabels){
					probe.probeLabels = new Array();
				}
	
				if (binding.probeLabel) {
					var probeLabel = binding.probeLabel.value;
					flyui.util.appendIfNotMember(probe.probeLabels, probeLabel);
				}
				image.probe = probe;
			}		
		}
		
		return imagePool.toArray();
	}catch (error) {
        throw new flyui.UnexpectedException("flyui.flyted.Image.newInstancesFromSPARQLResults", error);
    }
};


flyui.flyted.ImagePool = function() {
	/**
	 * @private
	 */
	this._pool = new Object();
};

flyui.flyted.ImagePool.prototype.toArray = function() {
	try {
		var array = new Array();
		for (var key in this._pool) {
			array[array.length] = this._pool[key];
		}
		return array;
	} catch (error) {
        throw new flyui.UnexpectedException("flyui.flyted.ImagePool.prototype.toArray", error);
    }
};

flyui.flyted.ImagePool.prototype.get = function( imagepath ) {
	
	try {
		var image = this._pool[imagepath];
	
		if ( typeof image == "undefined" || !image ) {
			image = new flyui.flyted.Image();
			image.fullImageURL = imagepath;		
			this._pool[imagepath] = image;	
		}
		
		return image;
	} catch (error) {
        throw new flyui.UnexpectedException("flyui.flyted.ImagePool.prototype.get", error);
    }
};

flyui.flyted.ProbePool = function() {
	/**
	 * @private
	 */
	this._pool = new Object();
};

flyui.flyted.ProbePool.prototype.get = function( probeURI ) {
	
	try {
		var probe = this._pool[probeURI];
		
		if (!probe ) {
			probe = new Object();
			probe.probeURI = probeURI;
			this._pool[probeURI] = probe;	
		}
		
		return probe;
	} catch (error) {
        throw new flyui.UnexpectedException("flyui.flyted.ProbePool.prototype.get", error);
    }
};

flyui.flyted.ProbePool.prototype.toArray = function() {
	try {
		var array = new Array();
		for (var key in this._pool) {
			array[array.length] = this._pool[key];
		}
		return array;
	} catch (error) {
        throw new flyui.UnexpectedException("flyui.flyted.ProbePool.prototype.toArray", error);
    }
};


flyui.flyted.Service.transformResponseForFindImagesByFlybaseGeneIDBatch = function( response ) {
    var _context = "flyui.flyted.Service.transformResponseForFindImagesByFlybaseGeneIDBatch";
    try {
        
        /* Turn results of query into result object like...
         * {
         *   "FBgn0036925" : {
         * 	{
         *     "fullImageURL": { "type": "uri" , "value": "http://www.fly-ted.org/767/2/wt01.bmp" } ,
         *	   "thumbnailURL": { "type": "uri" , "value": "http://www.fly-ted.org/767/thumbnails/2/medium.jpg" } ,
         * 	   "flytedURL": { "type": "uri" , "value": "http://www.fly-ted.org/767/" } ,
         *     "caption": { "type": "literal" , "value": "schuy in wt" } ,
         * 	   "probe": { "type": "uri" , "value": "http://openflydata.org/id/flyted/probe/schuy" } ,
         *     "probeLabel": { "type": "literal" , "value": "schuy" }
		 *	},
		 *  {
         *     "fullImageURL": { "type": "uri" , "value": "http://www.fly-ted.org/1478/2/cg17736-wt.jpg" } ,
         *     "thumbnailURL": { "type": "uri" , "value": "http://www.fly-ted.org/1478/thumbnails/2/medium.jpg" } ,
         *     "flytedURL": { "type": "uri" , "value": "http://www.fly-ted.org/1478/" } ,
         *     "caption": { "type": "literal" , "value": "CG17736/schuy in wt" } ,
         *     "probe": { "type": "uri" , "value": "http://openflydata.org/id/flyted/probe/schuy" } ,
         *      "probeLabel": { "type": "literal" , "value": "schuy" }
      	 *	} ,
		 *  ...
		 * },
         *   "FBgn0004903" : {
         {
         *     "fullImageURL": { "type": "uri" , "value": "http://www.fly-ted.org/2365/2/aly01.bmp" } ,
         *	   "thumbnailURL": { "type": "uri" , "value": "http://www.fly-ted.org/2365/thumbnails/2/medium.jpg" } ,
         * 	   "flytedURL": { "type": "uri" , "value": "http://www.fly-ted.org/2365/" } ,
         *     "caption": { "type": "literal" , "value": "Rb97D in aly" } ,
         * 	   "probe": { "type": "uri" , "value": "http://openflydata.org/id/flyted/probe/Rb97D" } ,
         *     "probeLabel": { "type": "literal" , "value": "Rb97D" }
		 *	},
		 *  {
         *     "fullImageURL": { "type": "uri" , "value": "http://www.fly-ted.org/2366/2/wt01.bmp" } ,
         *     "thumbnailURL": { "type": "uri" , "value": "http://www.fly-ted.org/2366/thumbnails/2/medium.jpg" } ,
         *     "flytedURL": { "type": "uri" , "value": "http://www.fly-ted.org/2366/" } ,
         *     "caption": { "type": "literal" , "value": "Rb97D in wt" } ,
         *     "probe": { "type": "uri" , "value": "http://openflydata.org/id/flyted/probe/Rb97D" } ,
         *     "probeLabel": { "type": "literal" , "value": "Rb97D" }
      	 *	},
      	 *  ....
      	 * }
         * }
         */

        flyui.debug("response status: "+response.status, _context);
        flyui.debug("try parsing response text as json", _context);
        flyui.debug("parsing response: "+response.responseText, _context);

        var resultSet = YAHOO.lang.JSON.parse(response.responseText);
        
        flyui.debug("convert result set to a map of fbgns to images indexed by fullImageURL", _context);
        
        var map = {};
        var imagePool = new flyui.flyted.ImagePool();
        var bindings = resultSet.results.bindings;
        
        for (var i=0; i<bindings.length; i++) {
            var binding = bindings[i];
            var fbgn = binding["fbgn"].value;
         
            var imagepath = binding["fullImageURL"].value;
            flyui.debug("add image : " + imagepath + " for gene " + fbgn, _context);
			var image = imagePool.get(imagepath);
			
			flyui.debug("get image object: " + image.fullImageURL + " for gene " + fbgn, _context);
			
			image.thumbnailURL = binding["thumbnailURL"].value;
			image.flytedURL = binding["flytedURL"].value;
			image.caption = binding["caption"].value;
						
            if (typeof map[fbgn] == "undefined" || !map[fbgn]) {
                flyui.debug("initialising gene label: "+fbgn, _context);
                map[fbgn] = {"images":[]};
            }
                        
            var images = map[fbgn].images;
                        
            flyui.util.appendIfNotMember(images, image);
                        
        }
            
        return map;
    
    } 
    catch (unexpected) {
        flyui.debug("rethrowing "+unexpected.name+", "+unexpected.message, _context);
        throw unexpected;    
    }    
};
